#include "Statistic.h"

Statistic::Statistic()
{
	name = sValue = sType = "";
	iValue = valflag = 0;
	parentList = NULL;
}

Statistic::Statistic( const Statistic& st )
{
	this->name = st.name;
	this->sValue = st.sValue;
	this->sType = st.sType;
	this->iValue = st.iValue;
	this->valflag = st.valflag;
	this->parentList = st.parentList;
}

Statistic::Statistic( const std::string& x, const std::string& y )
{
	name = x;
	sValue = y;
	valflag = 1;
	sType = "";
	parentList = NULL;
}

Statistic::Statistic( const std::string& x, int y )
{
	name = x;
	iValue = y;
	valflag = 2;
	sType = "";
	parentList = NULL;
}

void
Statistic::setValue( const std::string& x )
{
	this->sValue = x;
	if( !(valflag&1) ) valflag |= 1;
	sType = "";
}

void
Statistic::setValue( int x )
{
	this->iValue = x;
	if( !(valflag&2) ) valflag |= 2;
}

void
Statistic::setType( const std::string& t )
{
	this->sType = t;
}

void
Statistic::setName( const std::string& x )
{
	this->name = x;
}


std::string
Statistic::getsValue() const
{
	return this->sValue;
}

std::string
Statistic::getType() const
{
	return this->sType;
}

int
Statistic::getiValue() const
{
	return this->iValue;
}

std::string
Statistic::getName() const
{
	return this->name;
}

bool
Statistic::isInt() const
{
	return valflag & 2;
}

bool
Statistic::operator==( const Statistic& s ) const
{
	return !name.compare( s.getName() );
}

bool
Statistic::operator==( Statistic * s ) const
{
	return !name.compare( s->getName() );
}

bool
Statistic::operator==( const std::string& s ) const
{
	return !name.compare( s );
}


Statistic&
Statistic::operator=( int i )
{
	setValue(i);
	return *this;
}

Statistic&
Statistic::operator++( int i )
{
	setValue(getiValue()+1);
	return *this;
}

Statistic&
Statistic::operator--( int i )
{
	setValue(getiValue()-1);
	return *this;
}

Statistic&
Statistic::operator++()
{
	setValue(getiValue()+1);
	return *this;
}

Statistic&
Statistic::operator--()
{
	setValue(getiValue()-1);
	return *this;
}

Statistic&
Statistic::operator+=( int i )
{
	setValue(getiValue()+i);
	return *this;
}

Statistic&
Statistic::operator-=( int i )
{
	setValue(getiValue()-i);
	return *this;
}

Statistic&
Statistic::operator+=( const Statistic& s )
{
	setValue(getiValue()+s.getiValue());
	return *this;
}

Statistic&
Statistic::operator-=( const Statistic& s )
{
	setValue(getiValue()-s.getiValue());
	return *this;
}

int
Statistic::operator+( int i ) const
{
	return getiValue() + i;
}

int
Statistic::operator-( int i ) const
{
	return getiValue() - i;
}


Statistic&
Statistic::operator=( const std::string& s )
{
	setValue(s);
	return *this;
}

Statistic&
Statistic::operator=( const char * s )
{
	setValue(std::string(s));
	return *this;
}

Statistic&
Statistic::operator+=( const std::string& s )
{
	setValue(getsValue()+s);
	return *this;
}

Statistic&
Statistic::operator+=( const char * s )
{
	setValue(getsValue()+std::string(s));
	return *this;
}

std::string
Statistic::operator+( const std::string& s ) const
{
	return (std::string)(*this) + s;
}

std::string
Statistic::operator+( const char * s ) const
{
	return (std::string)(*this) + std::string(s);
}

Statistic&
Statistic::operator|=( const std::string& s )
{
	setType( s );
	return *this;
}

Statistic&
Statistic::operator|=( const char * s )
{
	setType( std::string( s ) );
	return *this;
}

Statistic::operator int() const
{
	return getiValue();
}

Statistic::operator std::string() const
{
	if( !(valflag & 1) && (valflag & 2) )
	{
		char buff[512];
		snprintf( buff, 512, "%d", getiValue() );
		return std::string( buff );
	}
	return getsValue();
}

std::string
Statistic::toString() const
{
	char cbuff[512];
	snprintf( cbuff, 512, "%d", getiValue() );
	std::string buff( cbuff );
	return "Stat(\"" + name + "\", " + buff + ", " + ( sType.length() ? sType + ":" : "" ) + "\"" + sValue + "\")";
}


StatList::StatList()
{

}

StatList::~StatList()
{
	for( unsigned int i = 0; i < statisticsList.length(); ++i )
		delete statisticsList[i];
	statisticsList.clear();
}

Statistic *
StatList::get( const std::string& statName ) const
{
	for( unsigned int i = 0; i < statisticsList.length(); ++i )
		if( statisticsList[i]->operator==( statName ) )
			return statisticsList[i];
	return NULL;
}

void
StatList::set( const std::string& statName, const std::string& sValue )
{
	Statistic * stat = this->get( statName );
	if( !stat )
	{
		stat = new Statistic( statName, sValue );
		stat->parentList = this;
		statisticsList += stat;
		return;
	}
	stat->setValue( sValue );
}

void
StatList::set( const std::string& statName, int iValue )
{
	Statistic * stat = this->get( statName );
	if( !stat )
	{
		stat = new Statistic( statName, iValue );
		stat->parentList = this;
		statisticsList += stat;
		return;
	}
	stat->setValue( iValue );
}

Statistic&
StatList::operator[] ( const std::string& statName )
{
	Statistic * stat = get( statName );
	if( !stat )
	{
		//std::cout << "Statistic[" << statName << "] ";
		//std::cout << "does not exist, creating empty stat value" << std::endl;
		stat = new Statistic();
		stat->setName(statName);
		stat->parentList = this;
		statisticsList += stat;
	}
	return *stat;
}

const
Statistic&
StatList::operator[] ( const std::string& statName ) const
{
	Statistic * stat = get( statName );
	if( !stat )
	{
		std::cout << "ERROR: Statistic[" << statName << "] ";
		std::cout << "does not exist, cannot create it in a const method" << std::endl;
		throw -1;
	}
	return *stat;
}

Statistic&
StatList::operator[] ( unsigned int i ) const
{
	return *statisticsList[ i ];
}

unsigned int
StatList::length() const
{
	return statisticsList.length();
}

StatList
StatList::operator + ( const StatList& stats ) const
{
	StatList ret;
	for( unsigned int i = 0; i < stats.length(); ++i )
	{
		ret.statisticsList += new Statistic( stats[ i ] );
		ret.statisticsList.last()->parentList = &ret;
	}
	for( unsigned int i = 0; i < length(); ++i )
	{
		Statistic * stat = ret.get( statisticsList[ i ]->getName() );
		if( stat )
		{
			stat->setValue( stat->getiValue() + statisticsList[ i ]->getiValue() );
			// use original string value
			stat->setValue( stat->getsValue() /*+ statisticsList[ i ]->getsValue()*/ );
		}
		else
		{
			ret.statisticsList += new Statistic( *statisticsList[ i ] );
			ret.statisticsList.last()->parentList = &ret;
		}
	}
	return ret;
}

StatList&
StatList::operator +=( const StatList& stats )
{
	for( unsigned int i = 0; i < stats.length(); ++i )
	{
		Statistic * stat = get( stats.statisticsList[ i ]->getName() );
		if( stat )
		{
			stat->setValue( stat->getiValue() + stats.statisticsList[ i ]->getiValue() );
			// override string values
			stat->setValue( /*stat->getsValue() +*/ stats.statisticsList[ i ]->getsValue() );
		}
		else
		{
			statisticsList += new Statistic( *stats.statisticsList[ i ] );
			statisticsList.last()->parentList = this;
		}
	}
	return *this;
}

StatList
StatList::operator| ( const std::string& ns ) const
{
	StatList ret;
	std::string ns2( ns );
	if( !ns2.length() )
		return ret;
	ns2 += ".";
	for( unsigned int i = 0; i < length(); ++i )
	{
		std::string nm = statisticsList[ i ]->getName();
		if( nm.length() && StringParser::startsWith( nm, ns2 ) )
		{
			Statistic * stat = new Statistic( *statisticsList[ i ] );
			nm = nm.substr( ns2.length() );
			stat->setName( nm );
			stat->parentList = &ret;
			ret.statisticsList += stat;
		}
	}
	return ret;
}

StatList
StatList::operator| ( const char * ns ) const
{
	StatList ret;
	std::string ns2( ns );
	if( !ns2.length() )
		return ret;
	ns2 += ".";
	for( unsigned int i = 0; i < length(); ++i )
	{
		std::string nm = statisticsList[ i ]->getName();
		if( nm.length() && StringParser::startsWith( nm, ns2 ) )
		{
			Statistic * stat = new Statistic( *statisticsList[ i ] );
			nm = nm.substr( ns2.length() );
			stat->setName( nm );
			stat->parentList = &ret;
			ret.statisticsList += stat;
		}
	}
	return ret;
}

StatList
StatList::combine( const StatList& stats, bool catint, bool catstr, const std::string& delimiter ) const
{
	StatList ret;
	for( unsigned int i = 0; i < stats.length(); ++i )
	{
		ret.statisticsList += new Statistic( stats[ i ] );
		ret.statisticsList.last()->parentList = &ret;
	}
	for( unsigned int i = 0; i < length(); ++i )
	{
		Statistic * stat = ret.get( statisticsList[ i ]->getName() );
		if( stat )
		{
			if( catint )
				stat->iValue += statisticsList[ i ]->iValue;
			if( catstr )
				stat->sValue += ( ( stat->sValue.length() ? delimiter : "" ) + statisticsList[ i ]->sValue );
			stat->parentList = &ret;
		}
		else
		{
			ret.statisticsList += new Statistic( *statisticsList[ i ] );
			ret.statisticsList.last()->parentList = &ret;
		}
	}
	return ret;
}
